package user;

import beans.UserLoginBean;
import beans.UserPageBean;
import controller.LeaveRemote;
import converters.LeaveModel;
import dtos.LeaveDTO;
import dtos.LeaveTypeDTO;
import dtos.UserDTO;
import org.primefaces.event.SelectEvent;
import org.primefaces.model.DefaultScheduleEvent;
import org.primefaces.model.DefaultScheduleModel;
import org.primefaces.model.ScheduleEvent;
import org.primefaces.model.ScheduleModel;
import utils.UserDAORemote;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

@ManagedBean
@SessionScoped
public class ScheduleBean {

    Logger LOG = Logger.getLogger(ScheduleBean.class.getName());

    private int totalPerYear = 21;
    private int bookedDays = 0;
    private int availableDays = 0;
    private int pendingDays = 0;


    @EJB
    private LeaveRemote leaveBean;

    @EJB
    private UserDAORemote userBean;

    @ManagedProperty(value = "#{userLoginBean}")
    private UserLoginBean loginBean;

    @ManagedProperty("#{userPageBean}")
    private UserPageBean upb;

    private ScheduleModel scheduleModel;

    private LeaveModel leaveEvent;
    private Date fromDate;
    private Date toDate;

    private List<LeaveTypeDTO> leaveTypes;

    @PostConstruct
    public void init() {
        //get all leaves, put them in schedule model
        scheduleModel = new DefaultScheduleModel();
        populateModel();
        leaveTypes = leaveBean.getLeaveTypes();
    }

    public void sendRequest(ActionEvent event) {
        long currentDiff = TimeUnit.DAYS.convert(toDate.getTime() - fromDate.getTime(), TimeUnit.MILLISECONDS);
        if (!leaveEvent.getReason().isEmpty() && dateIsValid() &&
                availableDays >= currentDiff) {

            leaveEvent.setFrom(fromDate);
            leaveEvent.setUntil(toDate);
            leaveEvent.setLeaveStatusDTO(leaveBean.getStatusForNew());

            UserDTO loggedU = (UserDTO) FacesContext.getCurrentInstance()
                    .getExternalContext().getSessionMap().get("loggedUser");

            leaveEvent.setUserDTO(loggedU);
            LeaveDTO leaveDTO = leaveBean.saveLeave(leaveEvent.getLeaveDTO());
            leaveEvent = new LeaveModel(leaveDTO, leaveBean, userBean);

            populateModel();
            upb.setPage("userSchedule");
            /*try {
                FacesContext.getCurrentInstance().getExternalContext().redirect("\\user\\userSchedule.xhtml");
            } catch (IOException ex) {
                ex.printStackTrace();
            }*/
        } else {
            FacesMessage message = new FacesMessage();
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            message.setSummary("Error!");
            if (availableDays >= currentDiff) {
                message.setDetail("Please specify a reason for your leave!");
            } else {
                message.setDetail("Your leave interval exceeds the available days.");
            }
            addMessage("title", message);

        }
    }


    public void deleteEvent(ActionEvent event) {
        leaveBean.deleteLeave(leaveEvent.getLeaveDTO().getId());
        populateModel();

        /*try {
            FacesContext.getCurrentInstance().getExternalContext().redirect("\\user\\userSchedule.xhtml");
        } catch (IOException ex) {
            ex.printStackTrace();
        }*/
    }

    public void onDateSelect(SelectEvent event) {
        leaveEvent = new LeaveModel(new LeaveDTO(), leaveBean, userBean);
//        leaveEvent.setFrom(new java.sql.Date(((Date) event.getObject()).getTime()));
//        leaveEvent.setUntil(new java.sql.Date(((Date) event.getObject()).getTime()));
        fromDate = (Date) event.getObject();
        toDate = (Date) event.getObject();
    }

    public void fromDateSelect(SelectEvent e) {
        if (((Date) e.getObject()).getTime() > toDate.getTime()) {
            toDate = (Date) e.getObject();
        }
    }

    public void toDateSelect(SelectEvent e) {
        if (((Date) e.getObject()).getTime() < fromDate.getTime()) {
            fromDate = (Date) e.getObject();
        }
    }

    public void onEventSelect(SelectEvent event) {
        leaveEvent = (LeaveModel) ((ScheduleEvent) event.getObject()).getData();
        fromDate = leaveEvent.getFrom();
        toDate = leaveEvent.getUntil();
    }

    public String refresh() {

        return null;
    }

    /**
     * *************************************************************************************
     */

    private void populateModel() {
        if (loginBean != null && loginBean.getLoggedUser() != null) {

            scheduleModel.clear();

            List<LeaveDTO> leaves = leaveBean.getLeaveByUserId(loginBean.getUserDTO().getId());
            for (LeaveDTO l : leaves) {
                LeaveModel lm = new LeaveModel(l, leaveBean, userBean);
                DefaultScheduleEvent defaultScheduleEvent = new DefaultScheduleEvent("[" +
                        lm.getLeaveStatusDTO().getName() + "] " +
                        lm.getReason(), lm.getFrom(), lm.getUntil(), lm);

                defaultScheduleEvent.setAllDay(true);
                scheduleModel.addEvent(defaultScheduleEvent);
            }
            dateIsValid();
            LOG.info("Populating schedule...");
        }
    }

    private boolean dateIsValid() {
        bookedDays = 0;
        availableDays = 0;
        pendingDays = 0;
        List<LeaveDTO> leaves = loginBean.getLoggedUser().getLeaves();
        for (LeaveDTO l : leaves) {
            if (l.getType() == 1) {
                long diff = TimeUnit.DAYS.convert(l.getUntil().getTime() - l.getFrom().getTime(), TimeUnit.MILLISECONDS);
                diff++;
                if (l.getStatus() == 1) {
                    pendingDays += diff;
                } else if (l.getStatus() == 2) {
                    bookedDays += diff;
                }
            }
        }
        availableDays = totalPerYear - bookedDays - pendingDays;

        return availableDays >= 0;
    }

    private void addMessage(String title, FacesMessage message) {
        FacesContext.getCurrentInstance().addMessage(null, message);
    }

    /**
     * *************************************************************************************
     */


    public ScheduleModel getScheduleModel() {
        return scheduleModel;
    }

    public void setScheduleModel(ScheduleModel scheduleModel) {
        this.scheduleModel = scheduleModel;
    }

    public UserLoginBean getLoginBean() {
        return loginBean;
    }

    public void setLoginBean(UserLoginBean loginBean) {
        this.loginBean = loginBean;
    }

    public LeaveModel getLeaveEvent() {
        return leaveEvent;
    }

    public void setLeaveEvent(LeaveModel leaveEvent) {
        this.leaveEvent = leaveEvent;
    }

    public Date getFromDate() {
        return fromDate;
    }

    public void setFromDate(Date fromDate) {
        this.fromDate = fromDate;
    }

    public Date getToDate() {
        return toDate;
    }

    public void setToDate(Date toDate) {
        this.toDate = toDate;
    }

    public List<LeaveTypeDTO> getLeaveTypes() {
        return leaveTypes;
    }

    public void setLeaveTypes(List<LeaveTypeDTO> leaveTypes) {
        this.leaveTypes = leaveTypes;
    }

    public int getTotalPerYear() {
        return totalPerYear;
    }

    public void setTotalPerYear(int totalPerYear) {
        this.totalPerYear = totalPerYear;
    }

    public int getBookedDays() {
        return bookedDays;
    }

    public void setBookedDays(int bookedDays) {
        this.bookedDays = bookedDays;
    }

    public int getAvailableDays() {
        return availableDays;
    }

    public void setAvailableDays(int availableDays) {
        this.availableDays = availableDays;
    }

    public int getPendingDays() {
        return pendingDays;
    }

    public void setPendingDays(int pendingDays) {
        this.pendingDays = pendingDays;
    }

    public UserPageBean getUpb() {
        return upb;
    }

    public void setUpb(UserPageBean upb) {
        this.upb = upb;
    }
}
